package com.echat.elocation.protocol.code;

import com.echat.elocation.constant.ProtocolConstant;
import com.echat.elocation.protocol.entity.PackageMsg;
import com.echat.elocation.protocol.entity.receive.RegisterRespMsg;
import com.echat.elocation.protocol.entity.receive.ServerCommonRespMsg;
import com.echat.elocation.protocol.entity.receive.TextMsgIssuedRespMsg;
import com.echat.elocation.util.BcdOperation;
import com.echat.elocation.util.BitOperation;
import com.echat.elocation.util.ProtocolUtils;

/**
 *  消息解码
 *
 * @author lihao
 *
 * @date 2018/7/16 16:25
 */
public class MsgDecoder {

    /**
     * 转换为服务器通用应答消息实体类
     *
     * @param msg 应答消息
     * @return
     */
    public ServerCommonRespMsg toServerCommonRepMsg(PackageMsg msg) {
        ServerCommonRespMsg ret = new ServerCommonRespMsg(msg);
        byte[] data = msg.getMsgBody();
        ret.setReplyFlowId(parseIntFromBytes(data, 0, 2));
        ret.setReplyId(parseIntFromBytes(data, 2, 2));
        ret.setReplyCode(parseIntFromBytes(data, 4, 1));
        return ret;
    }

    /**
     * 转换为注册应答消息实体类
     *
     * @param msg 应答消息
     * @return
     */
    public RegisterRespMsg toRegisterRepMsg(PackageMsg msg) {
        RegisterRespMsg ret = new RegisterRespMsg(msg);
        byte[] data = msg.getMsgBody();
        ret.setReplyFlowId(parseIntFromBytes(data, 0, 2));

        int result = parseIntFromBytes(data, 2, 1);
        ret.setReplyCode(result);
        if (result == 0) {
            ret.setReplyToken(parseStringFromBytes(data, 3, data.length - 3));
        }
        return ret;
    }

    public TextMsgIssuedRespMsg toTextMsgIssuedRepMsg(PackageMsg msg){
        TextMsgIssuedRespMsg ret = new TextMsgIssuedRespMsg(msg);
        byte[] data = msg.getMsgBody();

        int mark = parseIntFromBytes(data, 0, 1);
        int emergency = mark & 0x1;
        int reserve = mark & 0x2;
        int terminalShow = mark & 0x3;
        int ttsBroadcast = mark & 0x4;
        int advertisingScreenShow = mark & 0x5;
        int msgType = mark & 0x6;
        ret.setEmergency(emergency);
        ret.setReserve(reserve);
        ret.setTerminalShow(terminalShow);
        ret.setTTSBroadcast(ttsBroadcast);
        ret.setAdvertisingScreenShow(advertisingScreenShow);
        ret.setMsgType(msgType);
        ret.setMark(mark);

        String textMsg = parseStringFromBytes(data, 1, data.length - 1);
        ret.setTextMsg(textMsg);
        return ret;
    }


    public PackageMsg bytesToPackageMsg(byte[] data) {
        PackageMsg ret;
        try {
            ret = new PackageMsg();
            // 去掉首尾标识位，并转义
            byte[] dataSrc = ProtocolUtils.doEscape4Receive(data, 1, data.length - 2);
            // 消息头(12byte | 16byte)
            PackageMsg.MsgHeader msgHeader = parseMsgHeaderFromBytes(dataSrc);
            ret.setMsgHeader(msgHeader);

            int msgBodyStartIndex = 13;
            if (msgHeader.isHasSubPackage()) {
                msgBodyStartIndex = 16;
            }

            // 消息体
            byte[] body = new byte[msgHeader.getMsgBodyLength()];
            System.arraycopy(data, msgBodyStartIndex, body, 0, body.length);
            ret.setMsgBody(body);

            int checkCode = data[data.length - 2];
            byte[] headerAndBody = new byte[data.length - 3];
            System.arraycopy(data, 1, headerAndBody, 0, headerAndBody.length);
            byte calculatedCheckCode = ProtocolUtils.getCheckCode(headerAndBody, 0, headerAndBody.length);
            ret.setCheckCode(checkCode);
            if (checkCode != calculatedCheckCode) {
                System.out.println("检验码不一致");
            }
            return ret;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 将消息头字节数组转换为消息头实体类
     *
     * @param dataSrc
     * @return
     */
    private PackageMsg.MsgHeader parseMsgHeaderFromBytes(byte[] dataSrc) {
        PackageMsg.MsgHeader msgHeader = new PackageMsg.MsgHeader();
        // 去掉首尾标识位
        byte[] data = new byte[dataSrc.length - 2];
        System.arraycopy(dataSrc, 1, data, 0, dataSrc.length - 2);

        // 1. 消息ID word(2)
        msgHeader.setMsgId(parseIntFromBytes(data, 0, 2));
        // 2. 消息体属性 word(2)=================>
        int msgBodyProps = this.parseIntFromBytes(data, 2, 2);
        msgHeader.setMsgBodyProps(msgBodyProps);
        // [ 0-9 ] 0000,0011,1111,1111(3FF)(消息体长度)
        msgHeader.setMsgBodyLength(msgBodyProps & 0x3ff);
        // [10-12] 0001,1100,0000,0000(1C00)(加密类型)
        msgHeader.setEncryptionType((msgBodyProps & 0x01c00) >> 10);
        // [ 13_ ] 0010,0000,0000,0000(2000)(是否有子包)
        msgHeader.setHasSubPackage(((msgBodyProps & 0x2000) >> 13) == 1);
        // [14-15] 1100,0000,0000,0000(C000)(保留位)
        msgHeader.setReservedBit(((msgBodyProps & 0xc000) >> 14) + "");
        // 消息体属性 word(2)<=================

        // 3. 终端手机号 bcd[6]
        msgHeader.setPhoneNumber(parseBcdStringFromBytes(data, 4, 6));
        // 4. 消息流水号 word(16) 按发送顺序从 0 开始循环累加
        msgHeader.setFlowId(parseIntFromBytes(data, 10, 2));

        // 5. 消息包封装项
        // 有子包信息
        if (msgHeader.isHasSubPackage()) {
            // 消息包封装项字段
            msgHeader.setPackageInfoField(this.parseIntFromBytes(data, 12, 4));
            // byte[0-1] 消息包总数(word(16))
            msgHeader.setTotalSubPackage(this.parseIntFromBytes(data, 12, 2));

            // byte[2-3] 包序号(word(16)) 从 1 开始
            msgHeader.setSubPackageSeq(this.parseIntFromBytes(data, 12, 2));
        }
        return msgHeader;

    }

    private int parseIntFromBytes(byte[] data, int startIndex, int length) {
        try {
            // 字节数大于4,从起始索引开始向后处理4个字节,其余超出部分丢弃
            int len = length > 4 ? 4 : length;
            byte[] tmp = new byte[len];
            System.arraycopy(data, startIndex, tmp, 0, len);
            return BitOperation.byteToInteger(tmp);
        } catch (Exception e) {
            System.out.println("解析整数出错:{}" + e.getMessage());
            e.printStackTrace();
            return 0;
        }
    }

    private String parseStringFromBytes(byte[] data, int startIndex, int length) {
        try {
            byte[] tmp = new byte[length];
            System.arraycopy(data, startIndex, tmp, 0, length);
            return new String(tmp, ProtocolConstant.string_encoding);
        } catch (Exception e) {
            System.out.println("解析字符串出错:{}" + e.getMessage());
            e.printStackTrace();
            return null;
        }
    }

    private String parseBcdStringFromBytes(byte[] data, int startIndex, int length) {
        try {
            byte[] tmp = new byte[length];
            System.arraycopy(data, startIndex, tmp, 0, length);
            return BcdOperation.bcd2String(tmp);
        } catch (Exception e) {
            System.out.println("解析BCD(8421码)出错:{}" + e.getMessage());
            e.printStackTrace();
            return null;
        }
    }

}
